package com.weixing.mall.provider.config;

import com.weixing.mall.provider.auth.agent.password.AgentUserNameAndPasswordLoginConfig;
import com.weixing.mall.provider.auth.member.openid.MemberOpenIdLoginConfig;
import com.weixing.mall.provider.auth.member.password.MemberUserNameAndPasswordLoginConfig;
import com.weixing.mall.provider.auth.member.sms.MemberSmsCodeLoginConfig;
import com.weixing.mall.provider.auth.member.xcx.MemberXcxLoginConfig;
import com.weixing.mall.provider.auth.member.xcxAuth.MemberXcxAuthLoginConfig;
import com.weixing.mall.provider.auth.sys.SysUserNameAndPasswordLoginConfig;
import com.weixing.mall.provider.auth.sys.app.SysUserAppLoginConfig;
import com.weixing.mall.provider.constant.SecurityConstants;
import com.weixing.oauth2.common.properties.SecurityProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;

import javax.annotation.Resource;

/**
 * spring security配置
 * 在WebSecurityConfigurerAdapter不拦截oauth要开放的资源
 *
 * @author mall
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired(required = false)
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Resource
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Resource
    private LogoutHandler oauthLogoutHandler;

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    private SysUserNameAndPasswordLoginConfig sysUserNameAndPasswordLoginConfig;
    @Autowired
    private MemberUserNameAndPasswordLoginConfig memberUserNameAndPasswordLoginConfig;
    @Autowired
    private MemberSmsCodeLoginConfig memberSmsCodeLoginConfig;
    @Autowired
    private MemberOpenIdLoginConfig memberOpenIdLoginConfig;
    @Autowired
    private MemberXcxLoginConfig memberXcxLoginConfig;
    @Autowired
    private MemberXcxAuthLoginConfig memberXcxAuthLoginConfig;
    @Autowired
    private SysUserAppLoginConfig sysUserAppLoginConfig;
    @Autowired
    private AgentUserNameAndPasswordLoginConfig agentUserNameAndPasswordLoginConfig;
    /**
     * 这一步的配置是必不可少的，否则SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
     * @return 认证管理对象
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        log.info("configure");
        httpSecurity.headers().cacheControl();
        httpSecurity.authorizeRequests()
//                .antMatchers(securityProperties.getIgnore().getUrls())
                .antMatchers("/auth/**", "/oauth/**", "/login","/upload","/token/refresh","/token/check","/wechat","/member/login/**")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .logout()
                .logoutUrl(SecurityConstants.LOGOUT_URL)
                .logoutSuccessUrl(SecurityConstants.LOGIN_PAGE)
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
                .addLogoutHandler(oauthLogoutHandler)
                .clearAuthentication(true)
                .and()
                .apply(memberUserNameAndPasswordLoginConfig)
                .and()
                .apply(sysUserNameAndPasswordLoginConfig)
                .and()
                .apply(memberSmsCodeLoginConfig)
                .and()
                .apply(memberOpenIdLoginConfig)
                .and()
                .apply(memberXcxLoginConfig)
                .and()
                .apply(memberXcxAuthLoginConfig)
                .and()
                .apply(sysUserAppLoginConfig)
                .and()
                .apply(agentUserNameAndPasswordLoginConfig)
                .and()
                .csrf().disable()
                // 解决不允许显示在iframe的问题
                .headers().frameOptions().disable().cacheControl();

        // 基于密码 等模式可以无session,不支持授权码模式
        if (authenticationEntryPoint != null) {
            httpSecurity.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
            httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        } else {
            // 授权码模式单独处理，需要session的支持，此模式可以支持所有oauth2的认证
            httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        }
    }




    /**
     * 全局用户信息
     */
    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder authBuilder) throws Exception {
        authBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }


//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        super.configure(auth);
//        auth.
//    }
}
